package com.rfsp.common.interceptor;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

/**
 * @Component 将当前类注入到Spring容器内
 * @Aspect ：表明是一个切面类
 * @Before ：前置通知，在方法执行之前执行
 * @After ：后置通知，在方法执行之后执行
 * @AfterRuturning ：返回通知，在方法返回结果之后执行
 * @AfterThrowing ：异常通知，在方法抛出异常之后执行
 * @Around ：环绕通知，围绕着方法执行
 * @Pointcut ：切入点，PointCut（切入点）表达式有很多种，其中execution用于使用切面的连接点。
 * -----------------------------------
 * spring boot aop Before 输入参数 springboot中的aop
 *
 */
@Aspect
@Configuration
public class LogAspect {

    public Logger log = LoggerFactory.getLogger(LogAspect.class);

    @Pointcut("execution(public * com.rfsp.*.controller.*..*Controller.*(..))")
    public void log(){}

    @Before("log()")
    public void before(JoinPoint joinPoint) {
        try {
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            log.info("logger-begin:{}", signature);
            String name = signature.getName();

            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = null;
            if (attributes != null) {
                request = attributes.getRequest();
            }
            // 打印请求信息
            log.info("------------- 开始 -------------");
            log.info("请求地址: {} {}", request.getRequestURL().toString(), request.getMethod());
            log.info("类名方法: {}.{}", signature.getDeclaringTypeName(), name);
            log.info("远程地址: {}", request.getRemoteAddr());


            Method method = signature.getMethod();
            Parameter[] parameters = method.getParameters();
            Object[] args = joinPoint.getArgs();

            for (int i = 0; i < parameters.length; i++) {
                if (args[i] instanceof ServletRequest
                        || args[i] instanceof ServletResponse
                        || args[i] instanceof MultipartFile
                        || args[i] instanceof BindingResult
                        || args[i] instanceof ModelMap) {
                    continue;
                }
                log.debug("params-{}: {}[{}]", i, parameters[i].getName(), args[i]);
            }
        } catch (Exception e) {
            log.error("Exception:", e);
        }
    }

    @AfterReturning(returning = "ret", pointcut = "log()")
    public void after(JoinPoint joinPoint, Object ret) {
        log.info("logger-endle:{} ", joinPoint.getSignature());
        log.info("logger-return:{}", ret);
    }

    //异常通知
    @AfterThrowing(throwing = "ex", pointcut = "log()")
    public void exception(JoinPoint jp, Exception ex){
        log.error("Exception-method:{}", jp);
        log.error("Exception:", ex);
    }

}
